//============================================================================
// Name        : puzzle_path.cpp
// Author      : dfoelber
//============================================================================

// INCLUDES //
#include "physics/puzzle_path.h"
#include <iostream>
//////////////

using namespace std;

/**
* Constructor
* 
* @param width The width of the puzzle piece
* @param initialYVel Velocity of the path's falling
**/
PuzzlePath::PuzzlePath( int width, double initialYVel ) : 
	Path(),
	width(width)
{
	oldDir = DIRECTION_NONE;
	delayCounter = -1;
	rotate = false;
	baseYVel = yVel = initialYVel;
	SetAICommand(0);
}

/**
* Sets the path's listener
* 
* @param listener The new listener
**/
void PuzzlePath::SetListener( PuzzlePathListener* listener )
{
	this->listener = listener;
}

/**
* Notifies the path that an event has occurred.
* 
* Overridden from Path.
* 
* @param event The event that occurred
**/
void PuzzlePath::PuzzleEventOccurred( Path::PuzzleEvent event )
{
	if( rotate )
	{
		xDistance = 0;
	}
	
	for( int a = 0; a < (int)GetAssociations().size(); a++ )
	{
		GetAssociations()[a]->MoveDistance( -(GetAssociations()[a]->GetXDistance()), -(GetAssociations()[a]->GetYDistance()) );
		GetAssociations()[a]->MoveDistance( GetXDistance(), GetYDistance() );
	}
}

/**
* Lets the path know that time has passed and to move accordingly.
* 
* Overridden from Path.
* 
* @param ms The time passed since last called
**/
void PuzzlePath::TimePassed( int ms )
{
	yVel = baseYVel;
	if( keyDir == DIRECTION_DOWN || (aiCommand & COMMAND_DROP) > 0 )
	{
		yVel *= 70.0;
	}
	
	xDistance = yDistance = 0;
	yDistance = ((double)ms / 40.0) * yVel;
	
	if(delayCounter >= 0)
		delayCounter += ms;
	
	if(delayCounter >= KEY_DELAY)
	{
		keyDir = oldDir;
		delayCounter = 0;
	}
	
	if( keyDir == DIRECTION_RIGHT )
	{
		xDistance = width;
		
		oldDir = keyDir;
		delayCounter = 0;
		keyDir = DIRECTION_NONE;
	}
	else if( keyDir == DIRECTION_LEFT )
	{
		xDistance = -width;
		
		oldDir = keyDir;
		delayCounter = 0;
		keyDir = DIRECTION_NONE;
	}
	
	if( (aiCommand & COMMAND_ROTATE) > 0 )
	{
		rotate = true;
		aiCommand -= COMMAND_ROTATE;
	}
	
	if( rotate )
	{
		for( int a = 0; a < (int)GetAssociations().size(); a++ )
		{
			int xDiff = GetAssociations()[a]->GetX() - GetX();
			int yDiff = GetAssociations()[a]->GetY() - GetY();
			GetAssociations()[a]->MoveDistance( -(xDiff), -(yDiff) );
			if( GetAssociations()[a]->GetX() > GetX() && GetAssociations()[a]->GetY() <= GetY() )
			{
				GetAssociations()[a]->MoveDistance( yDiff, xDiff );
			}
			else if( GetAssociations()[a]->GetX() >= GetX() && GetAssociations()[a]->GetY() > GetY() )
			{
				GetAssociations()[a]->MoveDistance( -(yDiff), xDiff );
			}
			else if( GetAssociations()[a]->GetX() < GetX() && GetAssociations()[a]->GetY() >= GetY() )
			{
				GetAssociations()[a]->MoveDistance( -(yDiff), xDiff );
			}
			else if( GetAssociations()[a]->GetX() >= GetX() && GetAssociations()[a]->GetY() < GetY() )
			{
				GetAssociations()[a]->MoveDistance( -(yDiff), xDiff );
			}
		}
	}
	
	for( int a = 0; a < (int)GetAssociations().size(); a++ )
	{
		GetAssociations()[a]->MoveDistance(GetXDistance(), GetYDistance());
	}
}

/**
* Input that can be used by the path.
* 
* Overridden from Path.
* 
* @param event The event
* @return If the event was consumed
**/
bool PuzzlePath::Input( SDL_Event event )
{
	//If a key was pressed
    if( event.type == SDL_KEYDOWN )
    {
        //Adjust the velocity
        switch( event.key.keysym.sym )
        {
        	case SDLK_UP: 
        		rotate = true;
        		break;
            case SDLK_DOWN: keyDir = DIRECTION_DOWN; break;
            case SDLK_LEFT:
            	delayCounter = 0;
            	keyDir = DIRECTION_LEFT; 
            	break;
            case SDLK_RIGHT:
            	delayCounter = 0;
            	keyDir = DIRECTION_RIGHT; 
            	break; 
            case SDLK_SPACE:
            	rotate = true;
            	break;
            default:
            	break;
        }

		for( int a = 0; a < (int)GetAssociations().size(); a++ )
		{
			GetAssociations()[a]->SetRotating(rotate);
		}
        
        return true;
    }
    //If a key was released
    else if( event.type == SDL_KEYUP )
    {
    	delayCounter = -1;
    	keyDir = DIRECTION_NONE;       
        
        return true;
    }
    
    return false;
}

/**
* Check if this path collided with another path.
* 
* Overridden from Path.
* 
* @param other The other path.
**/
void PuzzlePath::CheckCollision( Path* other )
{
	/*if( (int)(side & SIDE_LEFT) == SIDE_LEFT )
	{
		for( int i = 0; i < (int)GetAssociations().size(); i++ )
		{
			GetAssociations()[i]->MoveDistance(GetXDistance() * -1, 0);
		}
		
		if( xDistance < 0 )
			xDistance = 0;
	}
	else if( (int)(side & SIDE_RIGHT) == SIDE_RIGHT )
	{
		for( int i = 0; i < (int)GetAssociations().size(); i++ )
		{
			GetAssociations()[i]->MoveDistance(GetXDistance() * -1, 0);
		}
		
		if( xDistance > 0 )
			xDistance = 0;
	}
	else if( (int)(side & SIDE_BOTTOM) == SIDE_BOTTOM )
	{
		if( yDistance > 0 )
			yDistance = other->GetY() - (GetHeight() + GetY());
		
		for( int i = 0; i < (int)GetAssociations().size(); i++ )
		{
			GetAssociations()[i]->MoveDistance(0, GetAssociations()[i]->GetYDistance() * -1);
			GetAssociations()[i]->MoveDistance(0, yDistance);
		}
	}
	
	if( rotate )
	{
		for( int a = 0; a < (int)GetAssociations().size(); a++ )
		{
			GetAssociations()[a]->MoveDistance( -(GetAssociations()[a]->GetXDistance()), -(GetAssociations()[a]->GetYDistance()) );
			GetAssociations()[a]->MoveDistance( GetXDistance(), GetYDistance() );
		}
	}*/
}

/**
* Sets the position of the path.
* 
* Overridden from Path.
* 
* @param x The new X coordinate
* @param y The new Y coordinate
**/
void PuzzlePath::SetPosition( int x, int y )
{
	this->x = x;
	this->y = y;
}

/**
* Gets if the path is still moving.
* 
* Overridden from Path.
* 
* @return If the path is moving
**/
bool PuzzlePath::IsMoving()
{
	return true;
}

/**
* Gets the Y velocity of the path.
* 
* Overridden from Path.
* 
* @return The current Y velocity
**/
double PuzzlePath::GetYVel() const
{
	// Some random constants, fix later?
	return baseYVel * (keyDir == DIRECTION_DOWN ? 20.0 : 2.0);
}
